#    Copyright 2012, Robert Baruch (robert.c.baruch@gmail.com)
#
#    This file is part of PYZ.
#
#    PYZ is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    PYZ is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with PYZ.  If not, see <http://www.gnu.org/licenses/>.

'''
Created on Jun 15, 2012

@author: robertbaruch
'''

import argparse
import sys
import os
from PyQt4 import QtCore, QtGui

import pyz

__version__ = "1.0.0"

class PyzGui(QtGui.QMainWindow):
    
    def __init__(self, parent = None):
        super(PyzGui, self).__init__(parent)
        self.resize(800, 600)
        self.central_widget = QtGui.QWidget(self)
        self.central_widget.setObjectName("Central Widget")
        
        self.status_widget = QtGui.QWidget(self.central_widget)
        self.status_widget.setObjectName("Status Widget")
        
        self.status_line_left = QtGui.QLabel(self.status_widget)
        self.status_line_left.setObjectName("Status Line Left")
        self.status_line_left.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
        
        self.status_line_right = QtGui.QLabel(self.status_widget)
        self.status_line_right.setObjectName("Status Line Right")
        self.status_line_right.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        
        layout = QtGui.QHBoxLayout(self.status_widget)
        layout.setObjectName("Status Widget Layout")
        layout.addWidget(self.status_line_left)
        layout.addWidget(self.status_line_right)
        layout.setContentsMargins(0, 0, 0, 0)
        
        self.text_output_area = QtGui.QTextEdit(self.central_widget)
        self.text_output_area.setObjectName("Text Output Area")
        self.text_output_area.setReadOnly(True)
        self.text_output_area.setStyleSheet("color: white; background-color: black")
        self.text_output_doc = self.text_output_area.document()
        self.text_output_cursor = QtGui.QTextCursor(self.text_output_doc)
        
        self.text_input_line = QtGui.QLineEdit(self.central_widget)
        self.text_input_line.setObjectName("Text Input Line")
        self.text_input_line.setStyleSheet("color: white; background-color: black")
        
        layout = QtGui.QVBoxLayout(self.central_widget)
        layout.setObjectName("Central Widget Layout")
        layout.addWidget(self.text_output_area)
        layout.addWidget(self.status_widget)
        layout.addWidget(self.text_input_line)
        
        self.setCentralWidget(self.central_widget)
        
        QtCore.QObject.connect(self.text_input_line, QtCore.SIGNAL("returnPressed()"), self.input_return_pressed)
        
        self.readline_mutex = QtCore.QMutex()
        self.readline_wait_condition = QtCore.QWaitCondition()
        
    def add_to_output(self, s):
        self.text_output_cursor.insertText(s)
        self.text_output_area.ensureCursorVisible()
        
    def update_status(self, obj, score):
        self.status_line_left.setText(obj)
        self.status_line_right.setText(score)
        
    def input_return_pressed(self):
        if self.zmachine_waiting_for_line:
            self.line = self.text_input_line.text()
            self.readline_wait_condition.wakeOne()
        self.text_input_line.clear()
        
    def readline(self):
        pass
    
    
class PyzProcessorThread(QtCore.QThread):
    
    def __init__(self, args, gui):
        super(PyzProcessorThread, self).__init__(gui)
        self.args = args
        self.gui = gui
        QtCore.QObject.connect(self, QtCore.SIGNAL("add_to_output"), gui.add_to_output)
        QtCore.QObject.connect(self, QtCore.SIGNAL("update_status"), gui.update_status)
        
    def run(self):
        memory = pyz.Memory(zfile = self.args.inputFile[0], zfilesize = os.path.getsize(self.args.inputFile[0].raw.name),
                            ostr = self, istr = self, sstr = self)
        print(memory.header)
        print(len(memory.memory))
        interpreter = pyz.Instruction_Interpreter(memory)
        loc = memory.header.initial_PC
        loc = interpreter.interpret(loc, trace=self.args.trace)
        
    def write(self, s):
        self.emit(QtCore.SIGNAL("add_to_output"), s)
        
    def update_status(self, obj, score):
        self.emit(QtCore.SIGNAL("update_status"), obj, score)
        
    def readline(self):
        self.gui.readline_mutex.lock()
        self.gui.zmachine_waiting_for_line = True
        print("Waiting for input")
        self.gui.readline_wait_condition.wait(self.gui.readline_mutex)
        self.line = self.gui.line
        print("Input is '" + self.line + "'")
        print(self.line, file = self)
        self.gui.readline_mutex.unlock()
        return self.line + "\n"
    
    
def main():
    app = QtGui.QApplication(sys.argv)
    
    parser = argparse.ArgumentParser(description='Z-Machine interpreter for Z-coded story files.')
    parser.add_argument('-V', '--version', action='version', version='%(prog)s 1.0 (2012-05-31)')
    parser.add_argument('-t', '--trace', action='store_true')
    parser.add_argument('inputFile', type=argparse.FileType('rb'), nargs=1,
                        help='The story file to run')
    
    args = parser.parse_args()
        
    gui = PyzGui()
    gui.show()
    gui.text_output_cursor.movePosition(QtGui.QTextCursor.End)
    thread = PyzProcessorThread(args, gui)
    thread.start()
    app.exec_()
    
        
if __name__ == '__main__':
    main()